/*
 * Copyright (C) 2007-2008  Vianney le Clément
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package fsahoraires.cours;

import static fsahoraires.cours.EmptyHoraire.EMPTY_HORAIRE;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Calendar;

public class Cours implements Comparable<Cours> {

	private final String code;
	private final CoursManager manager;
	private boolean disposed = false;
	String titre;
	private String abreviation;
	float credits;
	float heures;
	Horaire[] horaires = new Horaire[2];

	private void checkDisposed() {
		if (disposed)
			throw new IllegalStateException("This Cours has been disposed.");
	}

	public synchronized boolean isDisposed() {
		return disposed;
	}

	/**
	 * Crée un cours. Uniquement disponible par le {@link CoursManager}.
	 * <p>
	 * <i>Note:</i> visibilité package pour {@link CoursManager}. Ne dois pas
	 * être appelée en dehors!
	 * 
	 * @param code le code de cours (doit être en uppercase)
	 */
	Cours(String code, CoursManager manager) {
		if (code == null)
			throw new NullPointerException("code ne peut pas être null");
		this.code = code;
		this.manager = manager;
		titre = "";
		abreviation = "";
		credits = 0;
		heures = 0;
		horaires[0] = EMPTY_HORAIRE;
		horaires[1] = EMPTY_HORAIRE;
	}

	public synchronized String getCode() {
		return code;
	}

	public CoursManager getManager() {
		return manager;
	}

	public synchronized String getTitre() {
		return titre;
	}

	public void setTitre(String titre) {
		if (titre == null)
			throw new IllegalArgumentException("titre ne peut pas être null");
		manager.fireCoursBeforeModify(this);
		synchronized (this) {
			checkDisposed();
			this.titre = titre;
		}
		manager.fireCoursModified(this);
	}

	public synchronized String getAbreviation() {
		return abreviation;
	}

	public void setAbreviation(String abreviation) {
		if (abreviation == null)
			throw new IllegalArgumentException(
					"abreviation ne peut pas être null");
		manager.fireCoursBeforeModify(this);
		synchronized (this) {
			checkDisposed();
			this.abreviation = abreviation;
		}
		manager.fireCoursModified(this);
	}

	public synchronized float getCredits() {
		return credits;
	}

	public void setCredits(float credits) {
		manager.fireCoursBeforeModify(this);
		synchronized (this) {
			checkDisposed();
			this.credits = credits;
		}
		manager.fireCoursModified(this);
	}

	public synchronized float getHeures() {
		return heures;
	}

	public void setHeures(float heures) {
		manager.fireCoursBeforeModify(this);
		synchronized (this) {
			checkDisposed();
			this.heures = heures;
		}
		manager.fireCoursModified(this);
	}

	/**
	 * @param semestre le semestre (1 ou 2)
	 * @return l'horaire du semestre
	 */
	public synchronized Horaire getHoraire(int semestre) {
		return horaires[semestre - 1];
	}

	public void setHoraire(int semestre, Horaire horaire) {
		if (horaire == null)
			throw new IllegalArgumentException("horaire ne peut pas être null");
		manager.fireCoursBeforeModify(this);
		synchronized (this) {
			checkDisposed();
			horaires[semestre - 1] = horaire;
		}
		manager.fireCoursModified(this);
	}

	public synchronized URL getDescription() {
		try {
			checkDisposed();
			// FIXME smarter handling
			Calendar now = Calendar.getInstance();
			int year = now.get(Calendar.YEAR);
			if (now.get(Calendar.MONTH) < Calendar.APRIL)
				year--;
			return new URL("http://www.uclouvain.be/cours-" + year + "-"
					+ code.toLowerCase() + ".html");
		} catch (MalformedURLException e) {
			// Shouldn't occur
			e.printStackTrace();
			throw new NullPointerException();
		}
	}

	public synchronized void fetch(boolean description, boolean horaires) {
		checkDisposed();
		manager.getFetcher().add(this, description, horaires);
	}

	public synchronized void dispose() {
		manager.disposeCours(this);
		disposed = true;
	}

	public synchronized String toString() {
		checkDisposed();
		StringBuilder str = new StringBuilder(code);
		str.append(" - ").append(titre);
		return str.toString();
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == null)
			return false;
		if (!(obj instanceof Cours))
			return false;
		return (code == ((Cours) obj).code)
				&& (manager == ((Cours) obj).manager);
	}

	public int compareTo(Cours o) {
		return code.compareTo(o.code);
	}

}
